home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / wrlib / convert.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-04-02  |  26.6 KB  |  1,070 lines

  1. /* convert.c - convert RImage to Pixmap
  2.  * 
  3.  *  Raster graphics library
  4.  *
  5.  *  Copyright (c) 1997-2000 Alfredo K. Kojima 
  6.  *
  7.  *  This library is free software; you can redistribute it and/or
  8.  *  modify it under the terms of the GNU Library General Public
  9.  *  License as published by the Free Software Foundation; either
  10.  *  version 2 of the License, or (at your option) any later version.
  11.  *  
  12.  *  This library is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  *  Library General Public License for more details.
  16.  *  
  17.  *  You should have received a copy of the GNU Library General Public
  18.  *  License along with this library; if not, write to the Free
  19.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  */
  21. #include <config.h>
  22.  
  23.  
  24. #include <X11/Xlib.h>
  25. #include <X11/Xutil.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29.  
  30. #include <assert.h>
  31.  
  32. #ifdef BENCH
  33. #include "bench.h"
  34. #endif
  35.  
  36. #include "wraster.h"
  37.  
  38. #ifdef XSHM
  39. extern Pixmap R_CreateXImageMappedPixmap(RContext *context, RXImage *ximage);
  40.  
  41. #endif
  42.  
  43.  
  44. #ifdef ASM_X86
  45. extern void x86_PseudoColor_32_to_8(unsigned char *image,
  46.                  unsigned char *ximage, 
  47.                  char *err, char *nerr,
  48.                  short *ctable,
  49.                  int dr, int dg, int db,
  50.                  unsigned long *pixels,
  51.                  int cpc, 
  52.                  int width, int height,
  53.                  int bytesPerPixel,
  54.                  int line_offset);
  55. #endif /* ASM_X86 */
  56.  
  57. #ifdef ASM_X86_MMX
  58.  
  59. extern int x86_check_mmx();
  60.  
  61. extern void x86_mmx_TrueColor_32_to_16(unsigned char *image, 
  62.                        unsigned short *ximage,
  63.                        short *err, short *nerr,
  64.                        short *rtable, short *gtable,
  65.                        short *btable,
  66.                        int dr, int dg, int db,
  67.                        unsigned int roffs,
  68.                        unsigned int goffs, 
  69.                        unsigned int boffs, 
  70.                        int width, int height, 
  71.                        int line_offset);
  72.  
  73.  
  74.  
  75. #endif /* ASM_X86_MMX */
  76.  
  77.  
  78.  
  79. typedef struct RConversionTable {
  80.     unsigned short table[256];
  81.     unsigned short index;
  82.  
  83.     struct RConversionTable *next;
  84. } RConversionTable;
  85.  
  86.  
  87. typedef struct RStdConversionTable {
  88.     unsigned int table[256];
  89.  
  90.     unsigned short mult;
  91.     unsigned short max;
  92.  
  93.     struct RStdConversionTable *next;
  94. } RStdConversionTable;
  95.  
  96.  
  97.  
  98. static RConversionTable *conversionTable = NULL;
  99. static RStdConversionTable *stdConversionTable = NULL;
  100.  
  101.  
  102. static unsigned short*
  103. computeTable(unsigned short mask)
  104. {
  105.     RConversionTable *tmp = conversionTable;
  106.     int i;
  107.  
  108.     while (tmp) {
  109.         if (tmp->index == mask)
  110.             break;
  111.         tmp = tmp->next;
  112.     }
  113.  
  114.     if (tmp)
  115.         return tmp->table;
  116.  
  117.     tmp = (RConversionTable *)malloc(sizeof(RConversionTable));
  118.     if (tmp == NULL)
  119.         return NULL;
  120.  
  121.     for (i=0;i<256;i++)
  122.         tmp->table[i] = (i*mask + 0x7f)/0xff;
  123.  
  124.     tmp->index = mask;
  125.     tmp->next = conversionTable;
  126.     conversionTable = tmp;
  127.     return tmp->table;
  128. }
  129.  
  130.  
  131. static unsigned int*
  132. computeStdTable(unsigned int mult, unsigned int max)
  133. {
  134.     RStdConversionTable *tmp = stdConversionTable;
  135.     unsigned int i;
  136.  
  137.     while (tmp) {
  138.         if (tmp->mult == mult && tmp->max == max)
  139.             break;
  140.         tmp = tmp->next;
  141.     }
  142.  
  143.     if (tmp)
  144.         return tmp->table;
  145.  
  146.     tmp = (RStdConversionTable *)malloc(sizeof(RStdConversionTable));
  147.     if (tmp == NULL)
  148.         return NULL;
  149.  
  150.     for (i=0; i<256; i++) {
  151.         tmp->table[i] = (i*max)/0xff * mult;
  152.     }
  153.     tmp->mult = mult;
  154.     tmp->max = max;
  155.  
  156.     tmp->next = stdConversionTable;
  157.     stdConversionTable = tmp;
  158.  
  159.     return tmp->table;
  160. }
  161.  
  162. /***************************************************************************/
  163.  
  164.  
  165. static void
  166. convertTrueColor_generic(RXImage *ximg, RImage *image,
  167.              char *err, char *nerr,
  168.              const short *rtable, 
  169.              const short *gtable,
  170.              const short *btable,
  171.              const int dr, const int dg, const int db,
  172.              const unsigned short roffs,
  173.              const unsigned short goffs,
  174.              const unsigned short boffs)
  175. {
  176.     char *terr;
  177.     int x, y, r, g, b;
  178.     int pixel;
  179.     int rer, ger, ber;
  180.     unsigned char *ptr = image->data;
  181.     int channels = image->format == RRGBAFormat ? 4 : 3;
  182.     
  183.     /* convert and dither the image to XImage */
  184.     for (y=0; y<image->height; y++) {
  185.     nerr[0] = 0;
  186.     nerr[1] = 0;
  187.     nerr[2] = 0;
  188.     for (x=0; x<image->width; x++, ptr+=channels) {
  189.  
  190.         /* reduce pixel */
  191.         pixel = *ptr + err[x];
  192.         if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
  193.         r = rtable[pixel];
  194.         /* calc error */
  195.         rer = pixel - r*dr;
  196.  
  197.         /* reduce pixel */
  198.         pixel = *(ptr+1) + err[x+1];
  199.         if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
  200.         g = gtable[pixel];
  201.         /* calc error */
  202.         ger = pixel - g*dg;
  203.  
  204.         /* reduce pixel */
  205.         pixel = *(ptr+2) + err[x+2];
  206.         if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
  207.         b = btable[pixel];
  208.         /* calc error */
  209.         ber = pixel - b*db;
  210.  
  211.  
  212.         pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
  213.         XPutPixel(ximg->image, x, y, pixel);
  214.  
  215.         /* distribute error */
  216.         r = (rer*3)/8;
  217.         g = (ger*3)/8;
  218.         b = (ber*3)/8;
  219.         /* x+1, y */
  220.         err[x+3*1]+=r;
  221.         err[x+1+3*1]+=g;
  222.         err[x+2+3*1]+=b;
  223.         /* x, y+1 */
  224.         nerr[x]+=r;
  225.         nerr[x+1]+=g;
  226.         nerr[x+2]+=b;
  227.         /* x+1, y+1 */
  228.         nerr[x+3*1]=rer-2*r;
  229.         nerr[x+1+3*1]=ger-2*g;
  230.         nerr[x+2+3*1]=ber-2*b;
  231.     }
  232.     /* skip to next line */
  233.     terr = err;
  234.     err = nerr;
  235.     nerr = terr;
  236.     }
  237. }
  238.  
  239.  
  240.  
  241.  
  242. static RXImage*
  243. image2TrueColor(RContext *ctx, RImage *image)
  244. {
  245.     RXImage *ximg;
  246.     unsigned short rmask, gmask, bmask;
  247.     unsigned short roffs, goffs, boffs;
  248.     unsigned short *rtable, *gtable, *btable;
  249.     int channels = (image->format == RRGBAFormat ? 4 : 3);
  250.  
  251.     ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
  252.     if (!ximg) {
  253.     return NULL;
  254.     }
  255.  
  256.     roffs = ctx->red_offset;
  257.     goffs = ctx->green_offset;
  258.     boffs = ctx->blue_offset;
  259.     
  260.     rmask = ctx->visual->red_mask >> roffs;
  261.     gmask = ctx->visual->green_mask >> goffs;
  262.     bmask = ctx->visual->blue_mask >> boffs;
  263.  
  264.     rtable = computeTable(rmask);
  265.     gtable = computeTable(gmask);
  266.     btable = computeTable(bmask);
  267.  
  268.     if (rtable==NULL || gtable==NULL || btable==NULL) {
  269.     RErrorCode = RERR_NOMEMORY;
  270.         RDestroyXImage(ctx, ximg);
  271.         return NULL;
  272.     }
  273.  
  274.  
  275. #ifdef BENCH
  276.     cycle_bench(1);
  277. #endif
  278.  
  279.     if (ctx->attribs->render_mode==RBestMatchRendering) {
  280.     int ofs, r, g, b;
  281.     int x, y;
  282.     unsigned long pixel;
  283.     unsigned char *ptr = image->data;
  284.     
  285.         /* fake match */
  286. #ifdef DEBUG
  287.         puts("true color match");
  288. #endif
  289.     for (y=0, ofs=0; y < image->height; y++) {
  290.         for (x=0; x < image->width; x++, ofs+=channels-3) {
  291.         /* reduce pixel */
  292.                 r = rtable[ptr[ofs++]];
  293.                 g = gtable[ptr[ofs++]];
  294.                 b = btable[ptr[ofs++]];
  295.                 pixel = (r<<roffs) | (g<<goffs) | (b<<boffs);
  296.         XPutPixel(ximg->image, x, y, pixel);
  297.         }
  298.     }
  299.     } else {
  300.         /* dither */
  301.     const int dr=0xff/rmask;
  302.     const int dg=0xff/gmask;
  303.         const int db=0xff/bmask;
  304.  
  305. #ifdef DEBUG
  306.         puts("true color dither");
  307. #endif
  308.  
  309. #ifdef ASM_X86_MMX
  310.     if (ctx->depth == 16 && image->format == RRGBAFormat
  311.         && x86_check_mmx()) {
  312.         short *err;
  313.         short *nerr;
  314.  
  315.         err = malloc(8*(image->width+3));
  316.         nerr = malloc(8*(image->width+3));
  317.         if (!err || !nerr) {
  318.         if (nerr)
  319.             free(nerr);
  320.         RErrorCode = RERR_NOMEMORY;
  321.         RDestroyXImage(ctx, ximg);
  322.         return NULL;
  323.         }
  324.         memset(err, 0, 8*(image->width+3));
  325.         memset(nerr, 0, 8*(image->width+3));
  326.  
  327.         x86_mmx_TrueColor_32_to_16(image->data, 
  328.                        (unsigned short*)ximg->image->data, 
  329.                        err+8, nerr+8,
  330.                        rtable, gtable, btable,
  331.                        dr, dg, db, 
  332.                        roffs, goffs, boffs,
  333.                        image->width, image->height,
  334.                        ximg->image->bytes_per_line - 2*image->width);
  335.  
  336.         free(err);
  337.         free(nerr);
  338.     } else
  339. #endif /* ASM_X86_MMX */
  340.     {
  341.         char *err;
  342.         char *nerr;
  343.         int ch = image->format == RRGBAFormat ? 4 : 3;
  344.  
  345.         err = malloc(ch*(image->width+2));
  346.         nerr = malloc(ch*(image->width+2));
  347.         if (!err || !nerr) {
  348.         if (nerr)
  349.             free(nerr);
  350.         RErrorCode = RERR_NOMEMORY;
  351.         RDestroyXImage(ctx, ximg);
  352.         return NULL;
  353.         }
  354.         
  355.         memset(err, 0, ch*(image->width+2));
  356.         memset(nerr, 0, ch*(image->width+2));
  357.  
  358.         convertTrueColor_generic(ximg, image, err, nerr, 
  359.                      rtable, gtable, btable,
  360.                      dr, dg, db, roffs, goffs, boffs);
  361.         free(err);
  362.         free(nerr);
  363.     }
  364.  
  365.     }
  366.  
  367. #ifdef BENCH
  368.     cycle_bench(0);
  369. #endif
  370.  
  371.     return ximg;
  372. }
  373.  
  374.  
  375. /***************************************************************************/
  376.  
  377. static void
  378. convertPseudoColor_to_8(RXImage *ximg, RImage *image,
  379.                char *err, char *nerr,
  380.                const short *rtable, 
  381.                const short *gtable,
  382.                const short *btable,
  383.                const int dr, const int dg, const int db,
  384.                unsigned long *pixels,
  385.                int cpc)
  386. {
  387.     char *terr;
  388.     int x, y, r, g, b;
  389.     int pixel;
  390.     int rer, ger, ber;
  391.     unsigned char *ptr = image->data;
  392.     unsigned char *optr = ximg->image->data;
  393.     int channels = image->format == RRGBAFormat ? 4 : 3;
  394.     int cpcpc = cpc*cpc;
  395.  
  396.     /* convert and dither the image to XImage */
  397.     for (y=0; y<image->height; y++) {
  398.     nerr[0] = 0;
  399.     nerr[1] = 0;
  400.     nerr[2] = 0;
  401.     for (x=0; x<image->width*3; x+=3, ptr+=channels) {
  402.  
  403.         /* reduce pixel */
  404.         pixel = *ptr + err[x];
  405.         if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
  406.         r = rtable[pixel];
  407.         /* calc error */
  408.         rer = pixel - r*dr;
  409.  
  410.         /* reduce pixel */
  411.         pixel = *(ptr+1) + err[x+1];
  412.         if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
  413.         g = gtable[pixel];
  414.         /* calc error */
  415.         ger = pixel - g*dg;
  416.  
  417.         /* reduce pixel */
  418.         pixel = *(ptr+2) + err[x+2];
  419.         if (pixel<0) pixel=0; else if (pixel>0xff) pixel=0xff;
  420.         b = btable[pixel];
  421.         /* calc error */
  422.         ber = pixel - b*db;
  423.  
  424.         *optr++ = pixels[r*cpcpc + g*cpc + b];
  425.  
  426.         /* distribute error */
  427.         r = (rer*3)/8;
  428.         g = (ger*3)/8;
  429.         b = (ber*3)/8;
  430.  
  431.         /* x+1, y */
  432.         err[x+3*1]+=r;
  433.         err[x+1+3*1]+=g;
  434.         err[x+2+3*1]+=b;
  435.         /* x, y+1 */
  436.         nerr[x]+=r;
  437.         nerr[x+1]+=g;
  438.         nerr[x+2]+=b;
  439.         /* x+1, y+1 */
  440.         nerr[x+3*1]=rer-2*r;
  441.         nerr[x+1+3*1]=ger-2*g;
  442.         nerr[x+2+3*1]=ber-2*b;
  443.     }
  444.     /* skip to next line */
  445.     terr = err;
  446.     err = nerr;
  447.     nerr = terr;
  448.     
  449.     optr += ximg->image->bytes_per_line - image->width;
  450.     }
  451. }
  452.  
  453.  
  454.  
  455. static RXImage*
  456. image2PseudoColor(RContext *ctx, RImage *image)
  457. {
  458.     RXImage *ximg;
  459.     register int x, y, r, g, b;
  460.     unsigned char *ptr;
  461.     unsigned long pixel;
  462.     const int cpc=ctx->attribs->colors_per_channel;
  463.     const unsigned short rmask = cpc-1; /* different sizes could be used */
  464.     const unsigned short gmask = rmask; /* for r,g,b */
  465.     const unsigned short bmask = rmask;
  466.     unsigned short *rtable, *gtable, *btable;
  467.     const int cpccpc = cpc*cpc;
  468.     int channels = image->format == RRGBAFormat ? 4 : 3;
  469.  
  470.     ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
  471.     if (!ximg) {
  472.     return NULL;
  473.     }
  474.  
  475.     ptr = image->data;
  476.  
  477.     /* Tables are same at the moment because rmask==gmask==bmask. */
  478.     rtable = computeTable(rmask);
  479.     gtable = computeTable(gmask);
  480.     btable = computeTable(bmask);
  481.  
  482.     if (rtable==NULL || gtable==NULL || btable==NULL) {
  483.     RErrorCode = RERR_NOMEMORY;
  484.         RDestroyXImage(ctx, ximg);
  485.         return NULL;
  486.     }
  487.  
  488.     if (ctx->attribs->render_mode == RBestMatchRendering) {
  489.         /* fake match */
  490. #ifdef DEBUG
  491.         printf("pseudo color match with %d colors per channel\n", cpc);
  492. #endif
  493.     for (y=0; y<image->height; y++) {
  494.         for (x=0; x<image->width; x++, ptr+=channels-1) {
  495.         /* reduce pixel */
  496.                 r = rtable[*ptr++];
  497.                 g = gtable[*ptr++];
  498.                 b = btable[*ptr++];
  499.         pixel = r*cpccpc + g*cpc + b;
  500.                 /*data[ofs] = ctx->colors[pixel].pixel;*/
  501.                 XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel);
  502.         }
  503.     }
  504.     } else {
  505.     /* dither */
  506.     char *err;
  507.     char *nerr;
  508.     const int dr=0xff/rmask;
  509.     const int dg=0xff/gmask;
  510.     const int db=0xff/bmask;
  511.  
  512.  
  513. #ifdef DEBUG
  514.         printf("pseudo color dithering with %d colors per channel\n", cpc);
  515. #endif
  516.     err = malloc(4*(image->width+3));
  517.     nerr = malloc(4*(image->width+3));
  518.     if (!err || !nerr) {
  519.         if (nerr)
  520.         free(nerr);
  521.         RErrorCode = RERR_NOMEMORY;
  522.         RDestroyXImage(ctx, ximg);
  523.         return NULL;
  524.     }
  525.     memset(err, 0, 4*(image->width+3));
  526.     memset(nerr, 0, 4*(image->width+3));
  527.  
  528. /*#ifdef ASM_X86*/
  529. #if 0
  530.     x86_PseudoColor_32_to_8(image->data, ximg->image->data,
  531.                  err+4, nerr+4,
  532.                  rtable,
  533.                  dr, dg, db, ctx->pixels, cpc,
  534.                  image->width, image->height,
  535.                  channels, 
  536.                  ximg->image->bytes_per_line - image->width);
  537. #else
  538.     convertPseudoColor_to_8(ximg, image, err+4, nerr+4,
  539.                 rtable,    gtable,    btable,
  540.                 dr, dg, db, ctx->pixels, cpc);
  541. #endif
  542.  
  543.     free(err);
  544.     free(nerr);
  545.     }
  546.     
  547.     return ximg;
  548. }
  549.  
  550.  
  551. /*
  552.  * For standard colormap
  553.  */
  554. static RXImage*
  555. image2StandardPseudoColor(RContext *ctx, RImage *image)
  556. {
  557.     RXImage *ximg;
  558.     register int x, y, r, g, b;
  559.     unsigned char *ptr;
  560.     unsigned long pixel;
  561.     unsigned char *data;
  562.     unsigned int *rtable, *gtable, *btable;
  563.     unsigned int base_pixel = ctx->std_rgb_map->base_pixel;
  564.     int channels = image->format == RRGBAFormat ? 4 : 3;
  565.     /*register unsigned char maxrgb = 0xff;*/
  566.  
  567.     ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
  568.     if (!ximg) {
  569.     return NULL;
  570.     }
  571.  
  572.     ptr = image->data;
  573.     
  574.     data = (unsigned char *)ximg->image->data;
  575.  
  576.  
  577.     rtable = computeStdTable(ctx->std_rgb_map->red_mult,
  578.                  ctx->std_rgb_map->red_max);
  579.  
  580.     gtable = computeStdTable(ctx->std_rgb_map->green_mult,
  581.                  ctx->std_rgb_map->green_max);
  582.  
  583.     btable = computeStdTable(ctx->std_rgb_map->blue_mult,
  584.                  ctx->std_rgb_map->blue_max);
  585.  
  586.     if (rtable==NULL || gtable==NULL || btable==NULL) {
  587.     RErrorCode = RERR_NOMEMORY;
  588.         RDestroyXImage(ctx, ximg);
  589.         return NULL;
  590.     }
  591.  
  592.  
  593.     if (ctx->attribs->render_mode == RBestMatchRendering) {
  594.     for (y=0; y<image->height; y++) {
  595.         for (x=0; x<image->width; x++, ptr+=channels-3) {
  596.         /* reduce pixel */
  597.         pixel = (rtable[*ptr++] + gtable[*ptr++]
  598.              + btable[*ptr++] + base_pixel) & 0xffffffff;
  599.  
  600.                 XPutPixel(ximg->image, x, y, pixel);
  601.         }
  602.     }
  603.     } else {
  604.     /* dither */
  605.     short *err, *nerr;
  606.     short *terr;
  607.     int rer, ger, ber;
  608.     int x1, ofs;
  609.  
  610. #ifdef DEBUG
  611.         printf("pseudo color dithering with %d colors per channel\n", cpc);
  612. #endif
  613.     err = (short*)malloc(3*(image->width+2)*sizeof(short));
  614.     nerr = (short*)malloc(3*(image->width+2)*sizeof(short));
  615.     if (!err || !nerr) {
  616.         if (nerr)
  617.         free(nerr);
  618.         RErrorCode = RERR_NOMEMORY;
  619.         RDestroyXImage(ctx, ximg);
  620.         return NULL;
  621.     }
  622.     for (x=0, x1=0; x<image->width*3; x1+=channels-3) {
  623.         err[x++] = ptr[x1++];
  624.         err[x++] = ptr[x1++];
  625.         err[x++] = ptr[x1++];
  626.     }
  627.         err[x++] = err[x++] = err[x++] = 0;
  628.     /* convert and dither the image to XImage */
  629.     for (y=0, ofs=0; y<image->height; y++) {
  630.         if (y<image->height-1) {
  631.         int x1;
  632.         for (x=0, x1=(y+1)*image->width*channels;
  633.              x<image->width*3;
  634.              x1+=channels-3) {
  635.             nerr[x++] = ptr[x1++];
  636.             nerr[x++] = ptr[x1++];
  637.             nerr[x++] = ptr[x1++];
  638.         }
  639.         /* last column */
  640.         x1-=channels;
  641.         nerr[x++] = ptr[x1++];
  642.         nerr[x++] = ptr[x1++];
  643.         nerr[x++] = ptr[x1++];
  644.         }
  645.         for (x=0; x<image->width*3; x+=3, ofs++) {
  646.         /* reduce pixel */
  647.                 if (err[x]>0xff) err[x]=0xff; else if (err[x]<0) err[x]=0;
  648.                 if (err[x+1]>0xff) err[x+1]=0xff; else if (err[x+1]<0) err[x+1]=0;
  649.                 if (err[x+2]>0xff) err[x+2]=0xff; else if (err[x+2]<0) err[x+2]=0;
  650.  
  651.                 r = rtable[err[x]];
  652.                 g = gtable[err[x+1]];
  653.                 b = btable[err[x+2]];
  654.  
  655.         pixel = r + g + b;
  656.  
  657.                 data[ofs] = base_pixel + pixel;
  658.  
  659.         /* calc error */
  660.         rer = err[x] - (ctx->colors[pixel].red>>8);
  661.         ger = err[x+1] - (ctx->colors[pixel].green>>8);
  662.         ber = err[x+2] - (ctx->colors[pixel].blue>>8);
  663.  
  664.         /* distribute error */
  665.         err[x+3*1]+=(rer*7)/16;
  666.         err[x+1+3*1]+=(ger*7)/16;
  667.         err[x+2+3*1]+=(ber*7)/16;
  668.  
  669.         nerr[x]+=(rer*5)/16;
  670.         nerr[x+1]+=(ger*5)/16;
  671.         nerr[x+2]+=(ber*5)/16;
  672.  
  673.         if (x>0) {
  674.             nerr[x-3*1]+=(rer*3)/16;
  675.             nerr[x-3*1+1]+=(ger*3)/16;
  676.             nerr[x-3*1+2]+=(ber*3)/16;
  677.         }
  678.  
  679.         nerr[x+3*1]+=rer/16;
  680.         nerr[x+1+3*1]+=ger/16;
  681.         nerr[x+2+3*1]+=ber/16;
  682.         }
  683.         /* skip to next line */
  684.         terr = err;
  685.         err = nerr;
  686.         nerr = terr;
  687.  
  688.         ofs += ximg->image->bytes_per_line - image->width;
  689.     }
  690.     free(err);
  691.     free(nerr);
  692.     }
  693.     ximg->image->data = (char*)data;
  694.  
  695.     return ximg;
  696. }
  697.  
  698.  
  699.  
  700. static RXImage*
  701. image2GrayScale(RContext *ctx, RImage *image)
  702. {
  703.     RXImage *ximg;
  704.     register int x, y, g;
  705.     unsigned char *ptr;
  706.     const int cpc=ctx->attribs->colors_per_channel;
  707.     unsigned short gmask;
  708.     unsigned short *table;
  709.     unsigned char *data;
  710.     int channels = image->format == RRGBAFormat ? 4 : 3;
  711.  
  712.     /*register unsigned char maxrgb = 0xff;*/
  713.  
  714.     ximg = RCreateXImage(ctx, ctx->depth, image->width, image->height);
  715.     if (!ximg) {
  716.     return NULL;
  717.     }
  718.  
  719.     ptr = image->data;
  720.  
  721.     data = (unsigned char *)ximg->image->data;
  722.  
  723.     if (ctx->vclass == StaticGray)
  724.     gmask = (1<<ctx->depth) - 1; /* use all grays */
  725.     else
  726.     gmask  = cpc*cpc*cpc-1;
  727.  
  728.     table = computeTable(gmask);
  729.  
  730.     if (table==NULL) {
  731.     RErrorCode = RERR_NOMEMORY;
  732.         RDestroyXImage(ctx, ximg);
  733.         return NULL;
  734.     }
  735.  
  736.     if (ctx->attribs->render_mode == RBestMatchRendering) {
  737.         /* fake match */
  738. #ifdef DEBUG
  739.         printf("grayscale match with %d colors per channel\n", cpc);
  740. #endif
  741.     for (y=0; y<image->height; y++) {
  742.         for (x=0; x<image->width; x++) {
  743.                 /* reduce pixel */
  744.                 g = table[(*ptr++ * 30 + *ptr++ * 59 + *ptr++ * 11)/100];
  745.  
  746.                 /*data[ofs] = ctx->colors[g].pixel;*/
  747.                 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
  748.         }
  749.     }
  750.     } else {
  751.     /* dither */
  752.     short *gerr;
  753.     short *ngerr;
  754.     short *terr;
  755.     int ger;
  756.     const int dg=0xff/gmask;
  757.  
  758. #ifdef DEBUG
  759.         printf("grayscale dither with %d colors per channel\n", cpc);
  760. #endif
  761.     gerr = (short*)malloc((image->width+2)*sizeof(short));
  762.     ngerr = (short*)malloc((image->width+2)*sizeof(short));
  763.     if (!gerr || !ngerr) {
  764.         if (ngerr)
  765.         free(ngerr);
  766.         RErrorCode = RERR_NOMEMORY;
  767.         RDestroyXImage(ctx, ximg);
  768.         return NULL;
  769.     }
  770.     for (x=0; x<image->width; x++) {
  771.         gerr[x] = (ptr[x*3]*30 + ptr[x*3+1]*59 + ptr[x*3+2]*11)/100;
  772.     }
  773.     gerr[x] = 0;
  774.     /* convert and dither the image to XImage */
  775.     for (y=0; y<image->height; y++) {
  776.         if (y<image->height-1) {
  777.         int x1;
  778.         for (x=0, x1=(y+1)*image->width*3;
  779.              x<image->width; 
  780.              x1+=channels-3) {
  781.             ngerr[x] = (ptr[x1++]*30 + ptr[x1++]*59 + ptr[x1++]*11)/100;
  782.         }
  783.         /* last column */
  784.         x1-=channels;
  785.         ngerr[x] = (ptr[x1++]*30 + ptr[x1++]*59 + ptr[x1++]*11)/100;
  786.         }
  787.         for (x=0; x<image->width; x++) {
  788.         /* reduce pixel */
  789.                 if (gerr[x]>0xff) gerr[x]=0xff; else if (gerr[x]<0) gerr[x]=0;
  790.  
  791.                 g = table[gerr[x]];
  792.  
  793.                 /*data[ofs] = ctx->colors[g].pixel;*/
  794.                 XPutPixel(ximg->image, x, y, ctx->colors[g].pixel);
  795.         /* calc error */
  796.         ger = gerr[x] - g*dg;
  797.  
  798.         /* distribute error */
  799.         g = (ger*3)/8;
  800.         /* x+1, y */
  801.         gerr[x+1]+=g;
  802.         /* x, y+1 */
  803.         ngerr[x]+=g;
  804.         /* x+1, y+1 */
  805.         ngerr[x+1]+=ger-2*g;
  806.         }
  807.         /* skip to next line */
  808.         terr = gerr;
  809.         gerr = ngerr;
  810.         ngerr = terr;
  811.     }
  812.     free(gerr);
  813.     free(ngerr);
  814.     }
  815.     ximg->image->data = (char*)data;
  816.  
  817.     return ximg;
  818. }
  819.  
  820.  
  821. static RXImage*
  822. image2Bitmap(RContext *ctx, RImage *image, int threshold)
  823. {
  824.     RXImage *ximg;
  825.     unsigned char *alpha;
  826.     int x, y;
  827.  
  828.     ximg = RCreateXImage(ctx, 1, image->width, image->height);
  829.     if (!ximg) {
  830.     return NULL;
  831.     }
  832.     alpha = image->data+3;
  833.     
  834.     for (y = 0; y < image->height; y++) {
  835.     for (x = 0; x < image->width; x++) {
  836.         XPutPixel(ximg->image, x, y, (*alpha <= threshold ? 0 : 1));
  837.         alpha+=4;
  838.     }
  839.     }
  840.     
  841.     return ximg;
  842. }
  843.  
  844.  
  845.  
  846. int 
  847. RConvertImage(RContext *context, RImage *image, Pixmap *pixmap)
  848. {
  849.     RXImage *ximg=NULL;
  850. #ifdef XSHM
  851.     Pixmap tmp;
  852. #endif
  853.     
  854.     assert(context!=NULL);
  855.     assert(image!=NULL);
  856.     assert(pixmap!=NULL);
  857.  
  858.     /* clear error message */    
  859.     if (context->vclass == TrueColor) {
  860.  
  861.     ximg = image2TrueColor(context, image);
  862.  
  863.     } else if (context->vclass == PseudoColor 
  864.            || context->vclass == StaticColor) {
  865.  
  866. #ifdef BENCH
  867.     cycle_bench(1);
  868. #endif
  869.     if (context->attribs->standard_colormap_mode != RIgnoreStdColormap)
  870.         ximg = image2StandardPseudoColor(context, image);
  871.     else
  872.         ximg = image2PseudoColor(context, image);
  873. #ifdef BENCH
  874.     cycle_bench(0);
  875. #endif
  876.     } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
  877.  
  878.     ximg = image2GrayScale(context, image);
  879.     }
  880.  
  881.     if (!ximg) {
  882.     return False;
  883.     }
  884.  
  885.  
  886.     *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width,
  887.                 image->height, context->depth);
  888.     
  889. #ifdef XSHM
  890.     if (context->flags.use_shared_pixmap && ximg->is_shared)
  891.         tmp = R_CreateXImageMappedPixmap(context, ximg);
  892.     else
  893.     tmp = None;
  894.     if (tmp) {
  895.     /*
  896.      * We have to copy the shm Pixmap into a normal Pixmap because
  897.      * otherwise, we would have to control when Pixmaps are freed so
  898.      * that we can detach their shm segments. This is a problem if the
  899.      * program crash, leaving stale shared memory segments in the
  900.      * system (lots of them). But with some work, we can optimize
  901.      * things and remove this XCopyArea. This will require
  902.      * explicitly freeing all pixmaps when exiting or restarting
  903.      * wmaker.
  904.      */
  905.     XCopyArea(context->dpy, tmp, *pixmap, context->copy_gc, 0, 0,
  906.           image->width, image->height, 0, 0);
  907.     XFreePixmap(context->dpy, tmp);
  908.     } else {
  909.     RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
  910.            image->width, image->height);
  911.     }
  912. #else /* !XSHM */
  913.     RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0,
  914.            image->width, image->height);
  915. #endif /* !XSHM */
  916.  
  917.     RDestroyXImage(context, ximg);
  918.  
  919.     return True;
  920. }
  921.  
  922.  
  923. int 
  924. RConvertImageMask(RContext *context, RImage *image, Pixmap *pixmap, 
  925.           Pixmap *mask, int threshold)
  926. {
  927.     GC gc;
  928.     XGCValues gcv;
  929.     RXImage *ximg=NULL;
  930.  
  931.     assert(context!=NULL);
  932.     assert(image!=NULL);
  933.     assert(pixmap!=NULL);
  934.     assert(mask!=NULL);
  935.  
  936.     if (!RConvertImage(context, image, pixmap))
  937.     return False;
  938.     
  939.     if (image->format==RRGBFormat) {
  940.     *mask = None;
  941.     return True;
  942.     }
  943.  
  944.     ximg = image2Bitmap(context, image, threshold);
  945.     
  946.     if (!ximg) {
  947.     return False;
  948.     }
  949.     *mask = XCreatePixmap(context->dpy, context->drawable, image->width,
  950.               image->height, 1);
  951.     gcv.foreground = context->black;
  952.     gcv.background = context->white;
  953.     gcv.graphics_exposures = False;
  954.     gc = XCreateGC(context->dpy, *mask, GCForeground|GCBackground
  955.            |GCGraphicsExposures, &gcv);
  956.     RPutXImage(context, *mask, gc, ximg, 0, 0, 0, 0,
  957.            image->width, image->height);
  958.     RDestroyXImage(context, ximg);
  959.  
  960.     return True;
  961. }
  962.  
  963.  
  964. Bool
  965. RGetClosestXColor(RContext *context, RColor *color, XColor *retColor)
  966. {
  967.     if (context->vclass == TrueColor) {
  968.     unsigned short rmask, gmask, bmask;
  969.     unsigned short roffs, goffs, boffs;
  970.     unsigned short *rtable, *gtable, *btable;
  971.     
  972.     roffs = context->red_offset;
  973.     goffs = context->green_offset;
  974.     boffs = context->blue_offset;
  975.     
  976.     rmask = context->visual->red_mask >> roffs;
  977.     gmask = context->visual->green_mask >> goffs;
  978.     bmask = context->visual->blue_mask >> boffs;
  979.     
  980.     rtable = computeTable(rmask);
  981.     gtable = computeTable(gmask);
  982.     btable = computeTable(bmask);
  983.  
  984.         retColor->pixel = (rtable[color->red]<<roffs) |
  985.         (gtable[color->green]<<goffs) | (btable[color->blue]<<boffs);
  986.  
  987.     retColor->red = color->red << 8;
  988.     retColor->green = color->green << 8;
  989.     retColor->blue = color->blue << 8;
  990.     retColor->flags = DoRed|DoGreen|DoBlue;
  991.  
  992.     } else if (context->vclass == PseudoColor
  993.            || context->vclass == StaticColor) {
  994.  
  995.     if (context->attribs->standard_colormap_mode != RIgnoreStdColormap) {
  996.         unsigned int *rtable, *gtable, *btable;
  997.  
  998.         rtable = computeStdTable(context->std_rgb_map->red_mult,
  999.                      context->std_rgb_map->red_max);
  1000.  
  1001.         gtable = computeStdTable(context->std_rgb_map->green_mult,
  1002.                      context->std_rgb_map->green_max);
  1003.  
  1004.         btable = computeStdTable(context->std_rgb_map->blue_mult,
  1005.                      context->std_rgb_map->blue_max);
  1006.  
  1007.         if (rtable==NULL || gtable==NULL || btable==NULL) {
  1008.         RErrorCode = RERR_NOMEMORY;
  1009.         return False;
  1010.         }
  1011.  
  1012.         retColor->pixel = (rtable[color->red] 
  1013.                    + gtable[color->green]
  1014.                    + btable[color->blue] 
  1015.                    + context->std_rgb_map->base_pixel) & 0xffffffff;
  1016.         retColor->red = color->red<<8;
  1017.         retColor->green = color->green<<8;
  1018.         retColor->blue = color->blue<<8;
  1019.         retColor->flags = DoRed|DoGreen|DoBlue;
  1020.         
  1021.     } else {
  1022.         const int cpc=context->attribs->colors_per_channel;
  1023.         const unsigned short rmask = cpc-1; /* different sizes could be used */
  1024.         const unsigned short gmask = rmask; /* for r,g,b */
  1025.         const unsigned short bmask = rmask;
  1026.         unsigned short *rtable, *gtable, *btable;
  1027.         const int cpccpc = cpc*cpc;
  1028.         int index;
  1029.  
  1030.         rtable = computeTable(rmask);
  1031.         gtable = computeTable(gmask);
  1032.         btable = computeTable(bmask);
  1033.  
  1034.         if (rtable==NULL || gtable==NULL || btable==NULL) {
  1035.         RErrorCode = RERR_NOMEMORY;
  1036.         return False;
  1037.         }
  1038.         index = rtable[color->red]*cpccpc + gtable[color->green]*cpc 
  1039.         + btable[color->blue];
  1040.         *retColor = context->colors[index];
  1041.     }
  1042.  
  1043.     } else if (context->vclass == GrayScale || context->vclass == StaticGray) {
  1044.  
  1045.     const int cpc = context->attribs->colors_per_channel;
  1046.     unsigned short gmask;
  1047.     unsigned short *table;
  1048.     int index;
  1049.  
  1050.     if (context->vclass == StaticGray)
  1051.         gmask = (1<<context->depth) - 1; /* use all grays */
  1052.     else
  1053.         gmask  = cpc*cpc*cpc-1;
  1054.  
  1055.     table = computeTable(gmask);
  1056.     if (!table)
  1057.         return False;
  1058.  
  1059.     index = table[(color->red*30 + color->green*59 + color->blue*11)/100];
  1060.     
  1061.     *retColor = context->colors[index];
  1062.     } else {
  1063.     RErrorCode = RERR_INTERNAL;
  1064.     return False;
  1065.     }
  1066.  
  1067.     return True;
  1068. }
  1069.  
  1070.